package com.onlyxiahui.common.utils.base.security;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Base64.Decoder;

/**
 * 
 * Description <br>
 * Date 2020-11-09 10:50:32<br>
 * 
 * @author XiaHui [onlovexiahui@qq.com]<br>
 * @since 1.0.0
 */
public class CertificateUtil {

	private static Decoder base64Decoder = Base64.getMimeDecoder();
	public static final String KEY_ALGORITHM_0 = "RSA";
	public static final String KEY_ALGORITHM_1 = "RSA/ECB/PKCS1Padding";

	// private static Encoder base64Encoder = Base64.getEncoder();
	// private static BASE64Decoder base64Decoder=new BASE64Decoder();
	/**
	 * 
	 * Description 读取证书.cer、.crt文件<br>
	 * Date 2020-11-09 11:45:31<br>
	 * 
	 * @param filePath
	 * @return
	 * @since 1.0.0
	 */
	public static PublicKey getX509PublicKeyByFilePath(String filePath) {
		PublicKey key = null;
		X509Certificate certificate = getX509CertificateByFilePath(filePath);
		if (null != certificate) {
			key = certificate.getPublicKey();
		}
		return key;
	}

	/**
	 * 
	 * Description 读取证书.cer、.crt文件<br>
	 * Date 2020-11-09 11:45:44<br>
	 * 
	 * @param classPath
	 * @return
	 * @since 1.0.0
	 */
	public static PublicKey getX509PublicKeyByClassPath(String classPath) {
		PublicKey key = null;
		X509Certificate certificate = getX509CertificateByClassPath(classPath);
		if (null != certificate) {
			key = certificate.getPublicKey();
		}
		return key;
	}

	/******************************************/

	public static X509Certificate getX509CertificateByFilePath(String filePath) {
		X509Certificate certificate = null;
		try {
			FileInputStream is = new FileInputStream(filePath);
			certificate = getX509Certificate(is);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return certificate;
	}

	public static X509Certificate getX509CertificateByClassPath(String classPath) {
		InputStream is = CertificateUtil.class.getResourceAsStream(classPath);
		return getX509Certificate(is);
	}

	public static X509Certificate getX509Certificate(InputStream is) {
		X509Certificate certificate = null;
		if (null != is) {
			try {
				CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
				certificate = (X509Certificate) certificatefactory.generateCertificate(is);
			} catch (CertificateException e) {
				e.printStackTrace();
			} finally {
				if (null != is) {
					try {
						is.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
		return certificate;
	}

	/******************************************/

	public static PublicKey getPemRsaPublicKeyByFilePath(String filePath, String algorithm) {

		PublicKey key = null;
		try {
			String textKey = getTextKeyByFilePath(filePath);
			if (null != textKey) {
				key = convertPemRsaPublicKey(textKey, algorithm);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return key;
	}

	public static PublicKey getPemRsaPublicKeyByFilePath(String classPath) {
		return getPemRsaPublicKeyByFilePath(classPath, KEY_ALGORITHM_0);
	}

	public static PublicKey getPemRsaPublicKeyByClassPath(String classPath, String algorithm) {

		PublicKey key = null;
		try {
			String textKey = getTextKeyByClassPath(classPath);
			if (null != textKey) {
				key = convertPemRsaPublicKey(textKey, algorithm);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return key;
	}

	public static PublicKey getPemRsaPublicKeyByClassPath(String classPath) {
		return getPemRsaPublicKeyByClassPath(classPath, KEY_ALGORITHM_0);
	}

	/******************************************/

	public static PrivateKey getPemRsaPrivateKeyByFilePath(String filePath, String algorithm) {
		PrivateKey key = null;
		try {
			String textKey = getTextKeyByFilePath(filePath);
			if (null != textKey) {
				key = convertPemRsaPrivateKey(textKey, algorithm);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return key;
	}

	public static PrivateKey getPemRsaPrivateKeyByFilePath(String classPath) {
		return getPemRsaPrivateKeyByFilePath(classPath, KEY_ALGORITHM_0);
	}

	public static PrivateKey getPemRsaPrivateKeyByClassPath(String classPath, String algorithm) {
		PrivateKey key = null;
		try {
			String textKey = getTextKeyByClassPath(classPath);
			if (null != textKey) {
				key = convertPemRsaPrivateKey(textKey, algorithm);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return key;
	}

	public static PrivateKey getPemRsaPrivateKeyByClassPath(String classPath) {
		return getPemRsaPrivateKeyByClassPath(classPath, KEY_ALGORITHM_0);
	}

	/******************************************/

	public static PrivateKey convertPemRsaPrivateKey(String textKey, String algorithm) {
		PrivateKey key = null;
		try {
			// 获取KeyFactory，指定RSA算法
			KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
			byte[] encodeBytes = base64Decoder.decode(textKey);
			// 将BASE64解码后的字节数组，构造成PKCS8EncodedKeySpec对象，生成私钥对象
			key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodeBytes));
		} catch (NoSuchAlgorithmException e) {
			try {
				KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_0);
				byte[] encodeBytes = base64Decoder.decode(textKey);
				// 将BASE64解码后的字节数组，构造成PKCS8EncodedKeySpec对象，生成私钥对象
				key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodeBytes));
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return key;
	}

	public static PrivateKey convertPemRsaPrivateKey(String textKey) {
		return convertPemRsaPrivateKey(textKey, KEY_ALGORITHM_0);
	}

	public static PublicKey convertPemRsaPublicKey(String textKey, String algorithm) {
		PublicKey key = null;
		try {
			// 获取KeyFactory，指定RSA算法
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_1);
			// 将BASE64编码的公钥字符串进行解码
			byte[] encodeBytes = base64Decoder.decode(textKey);
//			byte[] encodeBytes = base64Decoder.decodeBuffer(textKey);
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodeBytes);
			// 将BASE64解码后的字节数组，构造成X509EncodedKeySpec对象，生成公钥对象
			key = keyFactory.generatePublic(keySpec);
		} catch (NoSuchAlgorithmException e) {
			try {
				// 获取KeyFactory，指定RSA算法
				KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_0);
				// 将BASE64编码的公钥字符串进行解码
				byte[] encodeBytes = base64Decoder.decode(textKey);
//						byte[] encodeBytes = base64Decoder.decodeBuffer(textKey);
				X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodeBytes);
				// 将BASE64解码后的字节数组，构造成X509EncodedKeySpec对象，生成公钥对象
				key = keyFactory.generatePublic(keySpec);
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return key;
	}

	public static PublicKey convertPemRsaPublicKey(String textKey) {
		return convertPemRsaPublicKey(KEY_ALGORITHM_0);
	}

	/******************************************/

	public static String getTextKeyByFilePath(String filePath) {
		String text = null;
		try {
			FileInputStream is = new FileInputStream(filePath);
			text = getTextKey(is);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return text;
	}

	public static String getTextKeyByClassPath(String classPath) {
		String text = null;
		text = getTextKey(CertificateUtil.class.getResourceAsStream(classPath));
		return text;
	}

	/**
	 * 
	 * Description 读取密钥文件 <br>
	 * Date 2020-11-09 14:30:22<br>
	 * 
	 * @param fis
	 * @return
	 * @since 1.0.0
	 */
	public static String getTextKey(InputStream input) {
		String text = null;
		if (null != input) {
			BufferedReader in = null;
			try {
				StringBuilder sb = new StringBuilder();

				in = new BufferedReader(new InputStreamReader(input));
				String temp;
				while ((temp = in.readLine()) != null) {
					if (temp.charAt(0) != '-') {
						sb.append(temp);
						sb.append("\r");
					}
				}
				text = (sb.length() == 0) ? null : sb.toString();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					if (null != input) {
						input.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				try {
					if (null != in) {
						in.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return text;
	}
}
